import { getCurrentInstance, inject, reactive, computed, toRefs } from "vue";
import { PiniaSymbol } from "./rootState";

function creatrOptionStore(id, options, pinia) {
  const { state, actions, getters = {} } = options;

  function setup() {
    // 用户提供的状态
    pinia.state.value[id] = state ? state() : {};
    const localState = toRefs(pinia.state.value[id]);
    return Object.assign(
      localState,
      actions, // 用户提供的动作
      Object.keys(getters).reduce((computeds, getterKey) => {
        computeds[getterKey] = computed(() => {
          return getters[getterKey].call(store);
        });
        return computeds;
      }, {})
    );
  }

  createSetupStore(id, setup, pinia); // options Api 需要将这个api转化成setup方法
}

// setupStore 用户中已经提供了完整的setup方法，我们只需要执行setup函数即可，通过这个返回值，将其放到store上就可以
function createSetupStore(id, setup, pinia) {
  // pinia就是创建了一个响应式对象而已
  const store = reactive({});

  function wrapAction(action) {
    return function () {
      // 将action中的this永远处理成store，保证this指向
      return action.call(store, ...arguments);
    };
  }

  const setupStore = setup(); // 拿到的setup可能没有处理过this指向

  for (let prop in setupStore) {
    const value = setupStore[prop];
    if (typeof value === "function") {
      // 将函数的this永远指向store
      setupStore[prop] = wrapAction(value);
    }
  }
  Object.assign(store, setupStore);
  pinia._s.set(id, store);
  return store;
}

export function defineStore(idOrOptions, setup) {
  let id;
  let options;

  const isSetupStore = typeof setup === "function"; //区分是optionsAPI还是setupAPI

  if (typeof idOrOptions === "string") {
    id = idOrOptions;
    options = setup;
  } else {
    options = idOrOptions;
    id = idOrOptions.id;
  }
  function useStore() {
    // useStore只能在组件中使用
    const currentInstance = getCurrentInstance();
    const pinia = currentInstance && inject(PiniaSymbol);

    if (!pinia._s.has(id)) {
      if (isSetupStore) {
        createSetupStore(id, options, pinia); //创建一个setupStore
      } else {
        // 创建选项store，还有可能是setupStore
        creatrOptionStore(id, options, pinia); // 创建后的store只需要存到_s中即可
      }
    }

    const store = pinia._s.get(id);
    console.log(pinia, 19);
    return store;
  }

  return useStore;
}
